package sk.stuba.fiit.ltasys.web.mvc.model.service.impl;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Service;

import sk.stuba.fiit.ltasys.web.mvc.model.dao.ArchiveDao;
import sk.stuba.fiit.ltasys.web.mvc.model.entity.ArchivePackageEntity;
import sk.stuba.fiit.ltasys.web.mvc.model.entity.EvidenceRecordEntity;
import sk.stuba.fiit.ltasys.web.mvc.model.entity.UserEntity;
import sk.stuba.fiit.ltasys.web.mvc.model.service.ArchiveService;
import sk.stuba.fiit.ltasys.web.mvc.model.service.UserService;
import sk.stuba.fiit.ltasys.web.mvc.model.service.core.ArchiveCreator;
import sk.stuba.fiit.ltasys.web.mvc.model.service.core.PackageForUserCreator;
import sk.stuba.fiit.ltasys.web.mvc.model.service.core.SignatureVerifier;
import sk.stuba.fiit.ltasys.ws.schema.beans.ArchiveRequest;
import sk.stuba.fiit.ltasys.ws.schema.beans.ArchiveResponse;
import sk.stuba.fiit.ltasys.ws.schema.beans.DataType;
import sk.stuba.fiit.ltasys.ws.schema.beans.SignatureRequest;
import sk.stuba.fiit.ltasys.ws.schema.beans.UserType;
import sk.stuba.fiit.ltasys.ws.service.MarshalingArchiveService;
import sun.misc.BASE64Decoder;


@Service("archiveService")
public class ArchiveServiceImpl implements ArchiveService{

	@Autowired
	private UserService userService;
	
	@Autowired 
	private ArchiveDao archiveDao;
	
	@Autowired 
	private Jaxb2Marshaller marshallerService;
	
	public boolean verifyUser(UserType user) {
		UserEntity dbuser = userService.findUserByUserName(user.getUserName());
		if(dbuser != null && dbuser.getPassword() != null){
			return dbuser.getPassword().equals(user.getUserPassword());
		}
		return false;
	}

	
	public List<String> parseUserData( DataType data ) throws Exception{
			List<String> fileNames = new ArrayList<String>();
			File tmpFile = null;
			try{
				BASE64Decoder decoder = new BASE64Decoder();
				byte [] binaryData = decoder.decodeBuffer(data.getBinaryData());
				long time = System.currentTimeMillis();
				tmpFile = new File(time+"tmp.zip");
				tmpFile.createNewFile();
				FileOutputStream fos = new FileOutputStream(tmpFile);
				fos.write(binaryData);
				fos.flush();
				fos.close();
				
				ZipInputStream inStream = new ZipInputStream(new FileInputStream(tmpFile));
				ZipEntry entry;
		        byte[] buffer = new byte[1024];
		        int nrBytesRead; 
		         
		        while ((entry = inStream.getNextEntry()) != null) {
		        	FileOutputStream fosUnzip = new FileOutputStream(new File(entry.getName()));
		        	fileNames.add(entry.getName());
		              while ((nrBytesRead = inStream.read(buffer)) > 0) {
		            	  fosUnzip.write(buffer, 0, nrBytesRead);
		               }
		            fosUnzip.close();
		        }
		                    
		        inStream.close();
				
				Source source = new StreamSource(new File("Signature.xml"));
				SignatureRequest archiveRequest = (SignatureRequest)marshallerService.unmarshal(source);
				
				tmpFile.delete();
				return fileNames;
			}catch (Exception e) {
				tmpFile.delete();
				throw e;
			}						
	}
	
	public void deleteUserFile(List<String> fileNames){
		for (String string : fileNames) {
			File f = new File(string);
			f.delete();
		}
	}

	public ArchiveResponse processArchiveRequest(ArchiveRequest request) {
		ArchiveResponse response = new ArchiveResponse();
		if(request.getAction().getArchive()!= null){
			try{
				List<String> userData = parseUserData(request.getData());
				try{
					String token = makeArchive(userData,request.getUser());
					DataType tokenresponse = new DataType();
					tokenresponse.setToken(token);
					response.setData(tokenresponse);
					response.setStatus(MarshalingArchiveService.DATA_ARCHIVED_SUCCESSFULLY);
					return response;
				}catch(Exception e){
					e.printStackTrace();
					response.setStatus(MarshalingArchiveService.DATA_NOT_ARCHIVED_SUCCESSFULLY);
					return response;
				}
			}catch(Exception e){	
				e.printStackTrace();
				response.setStatus(MarshalingArchiveService.INCORECT_DATA_FORMAT);
				return response;
			}
		
		}else{
			ArchivePackageEntity archive = archiveDao.loadArchivePackageByToken(request.getData().getToken());
			if(archive.getArchive_id() == 0){
				response.setStatus(MarshalingArchiveService.INCORECT_TOCEN);
				return response;
			}else{
				if(request.getAction().getDelete()!=null){
					try{
						deleteArchivePackage(archive);
						response.setStatus(MarshalingArchiveService.DATA_DELETED_SUCCESSFULLY);
						return response;
					}catch(Exception e){
						e.printStackTrace();
						response.setStatus(MarshalingArchiveService.DATA_NOT_DELETED_SUCCESSFULLY);
						return response;
					}
				}else if(request.getAction().getGetting() != null){
					try{
						response = createDataForUser(request.getUser(),request.getData().getToken());
						response.setStatus(MarshalingArchiveService.OPERATION_OK);
						return response;
					}catch(Exception e){
						e.printStackTrace();
						response.setStatus(MarshalingArchiveService.OPERATION_FAIL);
						return response;
					}
				}else{
					response.setStatus(MarshalingArchiveService.OPERATION_FAIL);
				}
			}
		}
		return response;
	}
	
@Autowired
private PackageForUserCreator packageCreator;

private ArchiveResponse createDataForUser(UserType user, String token) throws Exception {
		ArchivePackageEntity archivePackage =loadArchivePackageByToken(token);
		return packageCreator.assembleArchivePackage(archivePackage);
	}


@Autowired
private  SignatureVerifier signatureVerifier;

@Autowired
private ArchiveCreator archiveCreator;

	private String makeArchive(List<String> userFiles, UserType userType) throws Exception{
		Source source = new StreamSource(new File("Signature.xml"));
		SignatureRequest signatureRequest = (SignatureRequest)marshallerService.unmarshal(source);
		try{
		signatureVerifier.verifySignature(signatureRequest, userFiles);
		signatureVerifier.verifyTimestamp(signatureRequest);
		ArchivePackageEntity archivePackage =  archiveCreator.makeArchive(signatureRequest,userFiles,userType);
		saveArchivePackage(archivePackage);
		return archivePackage.getToken();
		}catch (Exception e) {
			e.printStackTrace();
		}		
		deleteUserFile(userFiles);
		throw new Exception();
	}


	public void saveArchivePackage(ArchivePackageEntity archivePackage) {
		archiveDao.saveArchivePackage(archivePackage);
		
	}

	public void deleteArchivePackage(ArchivePackageEntity archivePackage) {
		archiveDao.deleteArchivePackage(archivePackage);
		
	}

	public ArchivePackageEntity loadArchivePackageByToken(String token) {
		return archiveDao.loadArchivePackageByToken(token);
	}

	public List<ArchivePackageEntity> getAllArchivesByUser(UserEntity user) {
		return archiveDao.getAllArchivesByUser(user);
	}


	public EvidenceRecordEntity getArchiveRecordById(Integer id) {
		return archiveDao.getArchiveRecordById(id);
	}


	public List<ArchivePackageEntity> getAllRecordForRetimestamping() {
		return archiveDao.getAllRecordForRetimestamping();
	}
	
}
